package com.opengate.base.contextholder;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

/**
 * @author 曳戈泰尔
 * @version 1.0
 * @description Spring上下文工具类
 *     <p>Lazy(value = false)，如果value为true，则表示被注解的元素应该被懒加载；如果为false，则表示不应该被懒加载。
 * @date 2023/4/26 5:46 PM
 */
@Slf4j
@Component
@Lazy(value = false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

    // Spring应用上下文环境
    private static ApplicationContext applicationContext = null;

    /** 实现ApplicationContextAware接口的回调方法，设置上下文环境 */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHolder.applicationContext = applicationContext;
    }

    /** 实现DisposableBean接口的回调方法，销毁时清理静态变量 */
    @Override
    public void destroy() {
        SpringContextHolder.clearHolder();
    }

    /** 取得存储在静态变量中的ApplicationContext */
    public static ApplicationContext getApplicationContext() {
        assertContextInjected();
        return applicationContext;
    }

    /**
     * 从静态变量ApplicationContext中取得Bean，自动转型为所赋值对象的类型
     *
     * @param requiredType 类型
     * @param <T> 泛型
     * @return bean
     */
    public static <T> T getBean(Class<T> requiredType) {
        assertContextInjected();
        return applicationContext.getBean(requiredType);
    }

    /** 清除SpringContextHolder中的ApplicationContext为Null */
    public static void clearHolder() {
        log.info("清除SpringContextHolder中的ApplicationContext：{}", applicationContext);
        applicationContext = null;
    }

    /** 检查ApplicationContext不为空 */
    private static void assertContextInjected() {
        Validate.validState(
                applicationContext != null, "applicationContext属性未注入到SpringContextHolder");
    }
}
